package com.gyf.mybatis.sqlsession;

import com.gyf.mybatis.pojo.Configuration;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Proxy;
import java.lang.reflect.Type;
import java.util.List;

public class DefaultSqlSession implements SqlSession {
    private Configuration configuration;

    public DefaultSqlSession(Configuration configuration) {
        this.configuration = configuration;
    }

    @Override
    public <T> List<T> selectList(String statementId, Object... params) throws Exception {
        Executor executor = new SimpleExecutor();
        List<T> list = executor.query(configuration, configuration.getMappedStatementMap().get(statementId), params);
        return list;
    }

    @Override
    public <T> T selectOne(String statementId, Object... params) throws Exception {
        List<T> list = selectList(statementId, params);

        if (list.size() == 1) {
            return list.get(0);
        } else {
            throw new RuntimeException("selectOne error");
        }
    }

    @Override
    public <T> T getMapper(Class<?> mapperCls) {
        Object proxy = Proxy.newProxyInstance(DefaultSqlSession.class.getClassLoader(), new Class[]{mapperCls},
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        String methodName = method.getName();
                        String clsName = method.getDeclaringClass().getName().trim();
                        String statementId = clsName + "." + methodName;
                        Type genericReturnType = method.getGenericReturnType();
                        if (genericReturnType instanceof ParameterizedType) {
                            return selectList(statementId, args);
                        } else {
                            return selectOne(statementId, args);
                        }
                    }
                });
        return (T) proxy;
    }
}
